package com.wang.tool.monitor.translator;

import com.wang.tool.common.ErrorInfo;
import com.wang.tool.common.SimpleException;

import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeoutException;

/**
 * 默认异常翻译器
 *
 * @Author wangshaopeng
 * @Date 2022/6/20
 */
public class SimpleErrorTranslator implements ErrorTranslator {

    /**
     * 全局单例
     *
     * @return 非空
     */
    public static ErrorTranslator getInstance() {
        return Single.SINGLE;
    }

    /**
     * 翻译
     *
     * @param e 非空
     * @return
     */
    public static ErrorInfo simpleTranslate(Throwable e) {
        return Single.SINGLE.translate(e);
    }


    @Override
    public ErrorInfo translate(Throwable e) {
        //反射异常取源
        if (e instanceof InvocationTargetException) {
            e = ((InvocationTargetException) e).getTargetException();
        }
        //juc异步包抛出的异常都会进行包装
        if (e instanceof ExecutionException) {
            e = e.getCause();
        }
        String errorCode;
        String errorMsg = e.getMessage();
        if (e instanceof SimpleException) {
            errorCode = ((SimpleException) e).getCode();
        } else if (e instanceof IllegalArgumentException) {
            errorCode = SimpleException.PARAM_INVALID;
        } else {
            Class<? extends Throwable> errorType = e.getClass();
            if ("RpcException".equals(errorType.getSimpleName()) || errorType.getName().contains("dubbo")) {
                errorCode = SimpleException.RPC_ERROR;
            } else if (e instanceof TimeoutException) {
                errorCode = SimpleException.TIME_OUT;
            } else if (e instanceof NullPointerException) {
                errorCode = SimpleException.NPE;
            } else if (e instanceof RejectedExecutionException) {
                errorCode = SimpleException.EXECUTOR_BUSY;
            } else if (e instanceof InterruptedException) {
                errorCode = SimpleException.THREAD_INTERRUPT;
            } else if ("SentinelBlockException".equals(e.getMessage()) || errorType.getName().contains("sentinel")) {
                //sentinel异常
                errorCode = SimpleException.BIZ_FLOW_LIMIT;
            } else if (errorType.getName().contains("ibatis") || errorType.getName().contains("mybatis")) {
//              see MybatisMonitorInterceptor.handleError 细化异常码及变更sql敏感信息为mapper名称
//              最多找5层
                Throwable se = e;
                for (int i = 0; i < 10; i++) {
                    Throwable cause = se.getCause();
                    if (cause == null || cause == se) {
                        break;
                    }
                    if (cause instanceof SimpleException) {
                        se = cause;
                        break;
                    }
                    se = cause;
                }
                if (se instanceof SimpleException) {
                    errorCode = ((SimpleException) se).getCode();
                    errorMsg = se.getMessage();
                } else {
                    errorCode = SimpleException.DAO_ERROR;
                }
            } else {
                errorCode = errorType.getSimpleName();
            }
        }
        return ErrorInfo.build(e, errorCode, errorMsg);
    }


    public static class Single {
        public static final SimpleErrorTranslator SINGLE = new SimpleErrorTranslator();
    }
}
